package controllers

import (
	"bytes"
	"encoding/json"
	"github.com/astaxie/beego"
	ufsdk "github.com/ufilesdk-dev/ufile-gosdk"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"ufile_go/models"
)

const (
	configFile = "conf/ufile_config.json"
)

type UFileController struct {
	beego.Controller
}

// @Title api_fileList
// @Description 获取日志列表(默认只会获取hpc2仓库)
// @Param	body		body 	models.UFileModel	true		"body for UFileModel content"
// @Success 200 {object} file.FileListResponse
// @Failure 500 body is empty
// @router /api_fileList [post]
func (uFileController *UFileController) GetFileList() {
	var uFileModel models.UFileModel
	err := json.Unmarshal(uFileController.Ctx.Input.RequestBody, &uFileModel)
	checkErr(err)
	err, config := getConfig()
	checkErr(err)

	req, err := ufsdk.NewFileRequest(config, nil)
	checkErr(err)
	list, err := req.PrefixFileList(uFileModel.Prefix, uFileModel.Marker, uFileModel.Limit)
	resBaseJson(err, list, &uFileController.Controller)
}

// @Title api_bucketList
// @Description 获取仓库列表
// @Success 200 {object} bucket.BucketListResponse
// @Failure 500 {object}
// @router /api_bucketList [post]
func (uFileController *UFileController) GetBucketList() {
	err, config := getConfig()
	checkErr(err)
	req, err := ufsdk.NewBucketRequest(config, nil)
	checkErr(err)
	bucketList, err := req.DescribeBucket("", 0, 50, "")
	resBaseJson(err, bucketList, &uFileController.Controller)
}

// @Title api_downloadParsFile
// @Description 下载解析后文件(只会解析xlog,其余保留原始文件格式)
// @Param	body		body 	models.UFileDownloadModel	true		"body for UFileDownloadModel content"
// @Success 200 {object} string
// @Failure 500 body is empty
// @router /api_downloadParsFile [post]
func (uFileController *UFileController) DownloadParsFile() {
	var uFileDownloadModel models.UFileDownloadModel
	err := json.Unmarshal(uFileController.Ctx.Input.RequestBody, &uFileDownloadModel)
	checkErr(err)
	err, config := getConfig()
	checkErr(err)
	req, err := ufsdk.NewFileRequest(config, nil)
	checkErr(err)
	file, err := os.OpenFile(uFileDownloadModel.FileName, os.O_CREATE|os.O_WRONLY, 0755)
	checkErr(err)

	err = req.DownloadFile(file, uFileDownloadModel.FileName)
	checkErr(err)
	//检查后缀是否是xlog
	var fileName string
	if strings.Contains(uFileDownloadModel.FileName, ".xlog") {
		_, err := execShell("/usr/bin/python xlog/decode_mars_nocrypt_log_file.py " + uFileDownloadModel.FileName)
		if err != nil {
			fileName = uFileDownloadModel.FileName
			uFileController.Ctx.Output.Download(uFileDownloadModel.FileName)
			err = os.Remove(uFileDownloadModel.FileName)
			checkErr(err)
			//panic(err.Error())
		} else {
			fileName = uFileDownloadModel.FileName + ".log"
			uFileController.Ctx.Output.Download(uFileDownloadModel.FileName + ".log")
			err = os.Remove(uFileDownloadModel.FileName)
			err = os.Remove(uFileDownloadModel.FileName + ".log")
			checkErr(err)
		}
	} else {
		fileName = uFileDownloadModel.FileName
		uFileController.Ctx.Output.Download(uFileDownloadModel.FileName)
		err = os.Remove(uFileDownloadModel.FileName)
		checkErr(err)
	}
	resBaseJson(err, fileName, &uFileController.Controller)
}

// @Title api_downloadFile
// @Description 下载原始文件
// @Param	body		body 	models.UFileDownloadModel	true		"body for UFileDownloadModel content"
// @Success 200 {object} string
// @Failure 500 body is empty
// @router /api_downloadFile [post]
func (uFileController *UFileController) DownloadFile() {
	var uFileDownloadModel models.UFileDownloadModel
	err := json.Unmarshal(uFileController.Ctx.Input.RequestBody, &uFileDownloadModel)
	checkErr(err)
	err, config := getConfig()
	checkErr(err)
	req, err := ufsdk.NewFileRequest(config, nil)
	checkErr(err)
	file, err := os.OpenFile(uFileDownloadModel.FileName, os.O_CREATE|os.O_WRONLY, 0755)
	checkErr(err)

	err = req.DownloadFile(file, uFileDownloadModel.FileName)
	checkErr(err)
	uFileController.Ctx.Output.Download(uFileDownloadModel.FileName)
	err = os.Remove(uFileDownloadModel.FileName)
	checkErr(err)
	if err != nil {
		resBaseJson(err, "下载失败", &uFileController.Controller)
	} else {
		resBaseJson(err, "下载成功", &uFileController.Controller)
	}
}

// @Title api_downloadDecodePyFile
// @Description 下载微信提供的Python解析文件
// @Success 200 {object} string
// @Failure 500 body is empty
// @router /api_downloadDecodePyFile [post]
func (uFileController *UFileController) DownloadDecodePyFile() {
	uFileController.Ctx.Output.Download("./xlog/decode_mars_nocrypt_log_file.py")
	resBaseJson(nil, "下载成功", &uFileController.Controller)
}

// @Title api_deleteFile
// @Description 删除文件
// @Param	body		body 	models.UFileDeleteModel	true		"body for UFileDeleteModel content"
// @Success 200 {object} string
// @Failure 500 body is empty
// @router /api_deleteFile [post]
func (uFileController *UFileController) DeleteFile() {
	var uFileDeleteModel models.UFileDeleteModel
	err := json.Unmarshal(uFileController.Ctx.Input.RequestBody, &uFileDeleteModel)
	checkErr(err)
	err, config := getConfig()
	checkErr(err)
	req, err := ufsdk.NewFileRequest(config, nil)
	checkErr(err)
	err = req.DeleteFile(uFileDeleteModel.FileName)
	checkErr(err)
	resBaseJson(err, "删除成功", &uFileController.Controller)
}

//阻塞式的执行外部shell命令的函数,等待执行完毕并返回标准输出
func execShell(s string) (string, error) {
	//函数返回一个*Cmd，用于使用给出的参数执行name指定的程序
	cmd := exec.Command("/bin/bash", "-c", s)

	//读取io.Writer类型的cmd.Stdout，再通过bytes.Buffer(缓冲byte类型的缓冲器)将byte类型转化为string类型(out.String():这是bytes类型提供的接口)
	var out bytes.Buffer
	cmd.Stdout = &out

	//Run执行c包含的命令，并阻塞直到完成。  这里stdout被取出，cmd.Wait()无法正确获取stdin,stdout,stderr，则阻塞在那了
	err := cmd.Run()
	checkErr(err)
	return out.String(), err
}

//检查error
func checkErr(err error) {
	if err != nil {
		panic(err.Error())
	}
}

//获取ufile的配置信息
func getConfig() (error, *ufsdk.Config) {
	file, err := os.Open(configFile)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	configBytes, err := ioutil.ReadAll(file)
	if err != nil {
		panic(err)
	}
	config := new(ufsdk.Config)
	err = json.Unmarshal(configBytes, config)
	if err != nil {
		panic(err)
	}
	return err, config
}

//构造返回信息
func resBaseJson(err error, data interface{}, controller *beego.Controller) {
	baseResponseModel := new(models.BaseResponseModel)
	if err != nil {
		baseResponseModel.Code = 500
		baseResponseModel.Data = err.Error()
	} else {
		baseResponseModel.Code = 0
		baseResponseModel.Data = data
	}
	controller.Data["json"] = baseResponseModel
	controller.ServeJSON()
}
